home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / pico / browse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-14  |  31.6 KB  |  1,432 lines

  1. /*
  2.  * Program:    Routines to support file browser in pico and Pine composer
  3.  *
  4.  * Author:    Michael Seibel
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: mikes@cac.washington.edu
  11.  *
  12.  * Date:    4 April 1992
  13.  * Last Edited:    
  14.  *
  15.  * Copyright 1991 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  *
  35.  *
  36.  * NOTES:
  37.  *
  38.  *   Misc. thoughts (mss, 5 Apr 92)
  39.  * 
  40.  *      This is supposed to be just a general purpose browser, equally
  41.  *    callable from either pico or the pine composer.  Someday, it could
  42.  *     even be used to "wrap" the unix file business for really novice 
  43.  *      users.  The stubs are here for renaming, copying, creating directories,
  44.  *      deleting, undeleting (thought is delete just moves files to 
  45.  *      ~/.pico.deleted directory or something and undelete offers the 
  46.  *      files in there for undeletion: kind of like the mac trashcan).
  47.  *
  48.  *   Nice side effects
  49.  *
  50.  *      Since the full path name is always maintained and referencing ".." 
  51.  *      stats the path stripped of its trailing name, the unpleasantness of 
  52.  *      symbolic links is hidden.  
  53.  *
  54.  *   Fleshed out the file managements stuff (mss, 24 June 92)
  55.  *
  56.  *
  57.  */
  58. #include <stdio.h>
  59. #include <ctype.h>
  60. #include "osdep.h"
  61. #include "estruct.h"
  62. #include "edef.h"
  63. #include "pico.h"
  64.  
  65.  
  66.  
  67. /*
  68.  * useful external declarations
  69.  */
  70. extern char *prettysz(), *getfnames(), *getcwd(), *gethomedir();
  71.  
  72.  
  73. /* 
  74.  * useful internal declarations
  75.  */
  76. struct fcell *FindCell();
  77.  
  78.  
  79. /*
  80.  * directory cell structure
  81.  */
  82. struct fcell {
  83.     char *fname;                /* file name            */
  84.     unsigned mode;                /* file's mode           */
  85.     char size[16];                /* file's size in s    */
  86.     struct fcell *next;
  87.     struct fcell *prev;
  88. };
  89.  
  90.  
  91. /*
  92.  * master browser structure
  93.  */
  94. static struct bmaster {
  95.     struct fcell *head;                /* first cell in list  */
  96.     struct fcell *top;                /* cell in top left    */
  97.     struct fcell *current;            /* currently selected  */
  98.     int    longest;                /* longest file name   */
  99.     int       fpl;                    /* file names per line */
  100.     int    cpf;                    /* chars / file / line */
  101.     char   dname[NLINE];            /* this dir's name     */
  102.     char   *names;                /* malloc'd name array */
  103. } *gmp;                        /* global master ptr   */
  104.  
  105. /*
  106.  * function key mappings...
  107.  */
  108. static int  bfmappings[12][2] = { { F1,  '?'},    /* function key */
  109.                   { F2,  's'},    /* mappings... */
  110.                       { F3,  'c'},
  111.                         { F4,  'g'},
  112.                       { F5,  'r'},
  113.                        { F6,  'w'},
  114.                       { F7,  '-'},
  115.                       { F8,  ' '},
  116.                       { F9,  'd'},
  117.                       { F10, NODATA },
  118.                       { F11, 'm'},
  119.                       { F12, NODATA } };
  120.  
  121.  
  122. /*
  123.  * Browser help for pico (pine composer help handed to us by pine)
  124.  */
  125. static char *BrowseHelpText[] = {
  126. "Help for Browse Command",
  127. "  ",
  128. "\tPico's file browser is used to select a file from the",
  129. "\tfile system for inclusion in the edited text.",
  130. "  ",
  131. "~\tBoth directories and files are displayed.  Press ~S",
  132. "~\tor ~R~e~t~u~r~n to select a file or directory.  When a file",
  133. "\tis selected during the \"Read File\" command, it is",
  134. "\tinserted into edited text.  Answering \"yes\" to the",
  135. "\tverification question after a directory is selected causes",
  136. "\tthe contents of that directory to be displayed for selection.",
  137. "  ",
  138. "\tThe file named \"..\" is special, and means the \"parent\"",
  139. "\tof the directory being displayed.  Select this directory",
  140. "\tto move upward in the directory tree.",
  141. "  ",
  142. "End of Browser Help.",
  143. "  ",
  144. NULL
  145. };
  146.  
  147.  
  148.  
  149.  
  150.  
  151. /*
  152.  * FileBrowse - display contents of given directory dir
  153.  *
  154.  *         returns:
  155.  *                   dir points to currently selected directory
  156.  *                   fn  points to currently selected file
  157.  *                   sz  points to size of file if ptr passed was non-NULL
  158.  *                   1 if a file's been selected
  159.  *                   0 if no files seleted
  160.  *                  -1 if there where problems
  161.  */
  162. FileBrowse(dir, fn, sz)
  163. char *dir, *fn, *sz;            /* dir, name and optional size */
  164. {
  165.     int found = 0;
  166.     int status, i, j, c;
  167.     int row, col;
  168.     char *p, child[NLINE];
  169.     struct bmaster *mp, *getfcells();
  170.     struct fcell *tp;
  171.     extern char *HelpKeyNames;
  172.  
  173.     child[0] = '\0';
  174.  
  175.     if((gmode&MDSCUR) && homeless(dir)){
  176.     emlwrite("\007Can't read %s in restricted mode", dir);
  177.     sleep(2);
  178.     return(0);
  179.     }
  180.  
  181.     /* build contents of cell structures */
  182.     if((gmp = getfcells(dir)) == NULL)
  183.       return(-1);
  184.  
  185.     /* paint screen */
  186.     PaintBrowser(gmp, 0);
  187.  
  188.     while(1){                        /* the big loop */
  189.     movecursor(term.t_nrow-2, 0);
  190.  
  191.     (*term.t_flush)();
  192.  
  193.     c = GetKey();
  194.  
  195.     if(Pmaster){
  196.         if(c == NODATA || time_to_check()){        /* new mail ? */
  197.         if((*Pmaster->newmail)(&j, 0, c == NODATA ? 0 : 2) >= 0){
  198.             mlerase();
  199.             (*Pmaster->showmsg)(c);
  200.             mpresf = 1;
  201.         }
  202.         if(j)
  203.           (*term.t_move)(term.t_nrow-2, 0);
  204.  
  205.         if(c == NODATA)            /* GetKey timed out */
  206.           continue;
  207.         }
  208.     }
  209.     else{
  210.         if(timeout && (c == NODATA || time_to_check()))
  211.           if(pico_new_mail())
  212.         emlwrite("You may possibly have new mail.");
  213.         
  214.         if(c == NODATA)
  215.           continue;
  216.     }
  217.  
  218.     if(mpresf){                /* blast old messages */
  219.         if(mpresf++ > MESSDELAY){        /* every few keystrokes */
  220.         mlerase();
  221.         }
  222.         }
  223.  
  224.     switch(normal(c, bfmappings, 2)){    /* process commands */
  225.  
  226.       case K_PAD_RIGHT:            /* move right */
  227.       case (CTRL|'@'):
  228.       case (CTRL|'F'):            /* forward  */
  229.         if(gmp->current->next == NULL){
  230.         (*term.t_beep)();
  231.         break;
  232.         }
  233.  
  234.         PlaceCell(gmp, gmp->current, &row, &col);
  235.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  236.         gmp->current = gmp->current->next;
  237.         if(PlaceCell(gmp, gmp->current, &row, &col)){
  238.         PaintBrowser(gmp, 1);
  239.         }
  240.         else
  241.           PaintCell(row, col, gmp->cpf, gmp->current, 1);
  242.         break;
  243.  
  244.       case K_PAD_LEFT:                /* move left */
  245.       case (CTRL|'B'):                /* back */
  246.         if(gmp->current->prev == NULL){
  247.         (*term.t_beep)();
  248.         break;
  249.         }
  250.  
  251.         PlaceCell(gmp, gmp->current, &row, &col);
  252.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  253.         gmp->current = gmp->current->prev;
  254.         if(PlaceCell(gmp, gmp->current, &row, &col)){
  255.         PaintBrowser(gmp, 1);
  256.         }
  257.         else
  258.           PaintCell(row, col, gmp->cpf, gmp->current, 1);
  259.         break;
  260.  
  261.       case (CTRL|'A'):                /* beginning of line */
  262.         tp = gmp->current;
  263.         i = col;
  264.         while(i > 0){
  265.         i -= gmp->cpf;
  266.         if(tp->prev != NULL)
  267.           tp = tp->prev;
  268.         }
  269.         PlaceCell(gmp, gmp->current, &row, &col);
  270.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  271.         gmp->current = tp;
  272.         if(PlaceCell(gmp, tp, &row, &col)){
  273.         PaintBrowser(gmp, 1);
  274.         }
  275.         else
  276.           PaintCell(row, col, gmp->cpf, gmp->current, 1);
  277.         break;
  278.  
  279.       case (CTRL|'E'):                /* end of line */
  280.         tp = gmp->current;
  281.         i = col + gmp->cpf;
  282.         while(i+gmp->cpf <= gmp->cpf * gmp->fpl){
  283.         i += gmp->cpf;
  284.         if(tp->next != NULL)
  285.           tp = tp->next;
  286.         }
  287.  
  288.         PlaceCell(gmp, gmp->current, &row, &col);
  289.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  290.         gmp->current = tp;
  291.         if(PlaceCell(gmp, tp, &row, &col)){
  292.         PaintBrowser(gmp, 1);
  293.         }
  294.         else
  295.           PaintCell(row, col, gmp->cpf, gmp->current, 1);
  296.         break;
  297.  
  298.       case (CTRL|'V'):                /* page forward */
  299.       case ' ':
  300.         tp = gmp->top;
  301.         i = term.t_nrow - 4;
  302.  
  303.         while(i-- && tp->next != NULL){
  304.         j = 0;
  305.         while(++j <= gmp->fpl  && tp->next != NULL)
  306.           tp = tp->next;
  307.         }
  308.  
  309.         if(tp == NULL)
  310.           continue;
  311.  
  312.         PlaceCell(gmp, gmp->current, &row, &col);
  313.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  314.         gmp->current = tp;
  315.         if(PlaceCell(gmp, tp, &row, &col)){
  316.         PaintBrowser(gmp, 1);
  317.         }
  318.         else
  319.           PaintCell(row, col, gmp->cpf, gmp->current, 1);
  320.         break;
  321.  
  322.       case '-' :
  323.       case (CTRL|'Y'):                /* page backward */
  324.         tp = gmp->top;
  325.         i = term.t_nrow - 6;
  326.         while(i-- && tp != NULL){
  327.         j = gmp->fpl;
  328.         while(j-- && tp != NULL)
  329.           tp = tp->prev;
  330.         }
  331.  
  332.         if(tp || (gmp->current != gmp->top)){    /* clear old hilite */
  333.         PlaceCell(gmp, gmp->current, &row, &col);
  334.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  335.         }
  336.  
  337.         if(tp)                    /* new page ! */
  338.         gmp->current = tp;
  339.         else if(gmp->current != gmp->top)        /* goto top of page */
  340.         gmp->current = gmp->top;
  341.         else                    /* do nothing */
  342.           continue;
  343.  
  344.         if(PlaceCell(gmp, gmp->current, &row, &col)){
  345.         PaintBrowser(gmp, 1);
  346.         }
  347.         else
  348.           PaintCell(row, col, gmp->cpf, gmp->current, 1);
  349.  
  350.         break;
  351.  
  352.       case K_PAD_DOWN :
  353.       case (CTRL|'N'):                /* next */
  354.         tp = gmp->current;
  355.         i = gmp->fpl;
  356.         while(i--){
  357.         if(tp->next == NULL){
  358.             (*term.t_beep)();
  359.             break;
  360.         }
  361.         else
  362.           tp = tp->next;
  363.         }
  364.         if(i != -1)                    /* can't go down */
  365.           break;
  366.  
  367.         PlaceCell(gmp, gmp->current, &row, &col);
  368.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  369.         gmp->current = tp;
  370.         if(PlaceCell(gmp, tp, &row, &col)){
  371.         PaintBrowser(gmp, 1);
  372.         }
  373.         else
  374.           PaintCell(row, col, gmp->cpf, gmp->current, 1);
  375.         break;
  376.  
  377.       case K_PAD_UP :
  378.       case (CTRL|'P'):                /* previous */
  379.         tp = gmp->current;
  380.         i = gmp->fpl;
  381.         while(i-- && tp)
  382.           tp = tp->prev;
  383.  
  384.         if(tp == NULL)
  385.           break;
  386.  
  387.         PlaceCell(gmp, gmp->current, &row, &col);
  388.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  389.         gmp->current = tp;
  390.         if(PlaceCell(gmp, tp, &row, &col)){
  391.         PaintBrowser(gmp, 1);
  392.         }
  393.         else
  394.           PaintCell(row, col, gmp->cpf, gmp->current, 1);
  395.         break;
  396.  
  397.       case 'c':                    /* user aborts */
  398.       case 'C':
  399.         zotmaster(&gmp);
  400.         return(0);
  401.  
  402.       case 'd':                    /* delete */
  403.       case 'D':
  404.         if(gmp->current->mode){
  405.         emlwrite("\007Can't delete a directory", NULL);
  406.         break;
  407.         }
  408.  
  409.         if(gmode&MDSCUR){                /* not allowed! */
  410.         emlwrite("Delete not allowed in restricted mode",NULL);
  411.         break;
  412.         }
  413.  
  414.         sprintf(child, "%s%c%s", gmp->dname, C_FILESEP, 
  415.             gmp->current->fname);
  416.  
  417.         i = 0;
  418.         while(i++ < 2){        /* verify twice!! */
  419.         if(i == 1){
  420.             if(fexist(child, "w", (long *)NULL) != FIOSUC)
  421.               sprintf(s,"File is write protected! OVERRIDE", child);
  422.             else
  423.               sprintf(s, "Delete file \"%s\"", child);
  424.         }
  425.         else
  426.           strcpy(s, "File CANNOT be UNdeleted!  Really delete");
  427.  
  428.         if((status = mlyesno(s, FALSE)) != TRUE){
  429.             if(status ==  ABORT)
  430.               emlwrite("\007Delete Aborted");
  431.             else
  432.               emlwrite("File Not Deleted", NULL);
  433.             break;
  434.         }
  435.         }
  436.  
  437.         if(status == TRUE){
  438.         if(unlink(child) < 0){
  439.             extern int errno;
  440.             extern char *errstr();
  441.  
  442.             emlwrite("Delete Failed: %s", errstr(errno));
  443.         }
  444.         else{            /* fix up pointers and redraw */
  445.             tp = gmp->current;
  446.             if(tp->next){
  447.             gmp->current = tp->next;
  448.             if(tp->next->prev = tp->prev)
  449.               tp->prev->next = tp->next;
  450.             }
  451.             else if(tp->prev) {
  452.             gmp->current = tp->prev;
  453.             if(tp->prev->next = tp->next)
  454.               tp->next->prev = tp->prev;
  455.             }
  456.  
  457.             tp->fname = NULL;
  458.             tp->next = tp->prev = NULL;
  459.             if(tp != gmp->current)
  460.               free((char *) tp);
  461.  
  462.             if((tp = FindCell(gmp, gmp->current->fname)) != NULL){
  463.             gmp->current = tp;
  464.             PlaceCell(gmp, gmp->current, &row, &col);
  465.             }
  466.                 
  467.             PaintBrowser(gmp, 1);
  468.             mlerase();
  469.         }
  470.         }
  471.         break;
  472.  
  473.       case '?':                    /* HELP! */
  474.         if(Pmaster)
  475.           (*Pmaster->helper)(Pmaster->browse_help,
  476.                  "Help for Browsing", 1);
  477.         else
  478.           pico_help(BrowseHelpText, "Help for Browsing", 1);
  479.         /* fall thru to repaint everything */
  480.  
  481.       case (CTRL|'L'):
  482.         PaintBrowser(gmp, 0);
  483.         break;
  484.  
  485.       case 'g':                /* jump to a directory */
  486.       case 'G':
  487.         i = 0;
  488.         child[0] = '\0';
  489.  
  490.         while(!i){
  491.  
  492.         wkeyhelp("GC0000000000", "Get Help,Cancel");
  493.  
  494.         status = mlreply("Directory to go to: ", child, NLINE, QFFILE);
  495.  
  496.         switch(status){
  497.           case HELPCH:
  498.             emlwrite("\007No help yet!");
  499. /* remove break and sleep after help text is installed */
  500.             sleep(3);
  501.             break;
  502.           case (CTRL|'L'):
  503.             PaintBrowser(gmp, 0);
  504.             break;
  505.           case ABORT:
  506.             emlwrite("Aborted");
  507.             i++;
  508.             break;
  509.           case FALSE:
  510.           case TRUE:
  511.             i++;
  512.  
  513.             if(*child == '\0')
  514.               strcpy(child, gethomedir(NULL));
  515.  
  516.             if(!compresspath(gmp->dname, child, NLINE)){
  517.             emlwrite("Invalid Directory: %s", child);
  518.             break;
  519.             }
  520.  
  521.             if((gmode&MDSCUR) && homeless(child)){
  522.             emlwrite("Restricted mode browsing limited to home directory",NULL);
  523.             break;
  524.             }
  525.  
  526.             if(isdir(child, (long *) NULL)){
  527.             if((mp = getfcells(child)) == NULL){
  528.                 /* getfcells should explain what happened */
  529.                 i++;
  530.                 break;
  531.             }
  532.  
  533.             zotmaster(&gmp);
  534.             gmp = mp;
  535.             PaintBrowser(gmp, 0);
  536.             }
  537.             else
  538.               emlwrite("\007Not a directory: \"%s\"", child);
  539.  
  540.             break;
  541.           default:
  542.             break;
  543.         }
  544.         }
  545.         BrowserKeys();
  546.         break;
  547.  
  548.       case 'm':                    /* copy */
  549.       case 'M':
  550.         if(gmp->current->mode){
  551.         emlwrite("\007Can't copy a directory", NULL);
  552.         break;
  553.         }
  554.  
  555.         if(gmode&MDSCUR){                /* not allowed! */
  556.         emlwrite("Copy not allowed in restricted mode",NULL);
  557.         break;
  558.         }
  559.  
  560.         i = 0;
  561.         child[0] = '\0';
  562.  
  563.         while(!i){
  564.  
  565.         wkeyhelp("GC0000000000", "Get Help,Cancel");
  566.  
  567.         switch(status=mlreply("Name of new copy: ", child, NLINE, QFFILE)){
  568.           case HELPCH:
  569.             emlwrite("\007No help yet!");
  570. /* remove break and sleep after help text is installed */
  571.             sleep(3);
  572.             break;
  573.           case (CTRL|'L'):
  574.             PaintBrowser(gmp, 0);
  575.             break;
  576.           case ABORT:
  577.             emlwrite("Make Copy Aborted");
  578.             i++;
  579.             break;
  580.           case FALSE:
  581.             i++;
  582.             mlerase();
  583.             break;
  584.           case TRUE:
  585.             i++;
  586.  
  587.             if(child[0] == '\0'){
  588.             emlwrite("No destination, file not copied", NULL);
  589.             break;
  590.             }
  591.  
  592.             if(!strcmp(gmp->current->fname, child)){
  593.             emlwrite("\007Can't copy file on to itself!", NULL);
  594.             break;
  595.             }
  596.  
  597.             strcpy(s, child);         /* add full path! */
  598.             sprintf(child, "%s%c%s", gmp->dname, C_FILESEP, s);
  599.  
  600.             if((status = fexist(child, "w", (long *)NULL)) == FIOSUC){
  601.             sprintf(s,"File \"%s\" exists! OVERWRITE", child);
  602.             if((status = mlyesno(s, 0)) != TRUE){
  603.                 if(status == ABORT)
  604.                   emlwrite("\007Make Copy Aborted");
  605.                 else
  606.                   emlwrite("File Not Renamed", NULL);
  607.                 break;
  608.             }
  609.             }
  610.             else if(status != FIOFNF){
  611.             fioperr(status, child);
  612.             break;
  613.             }
  614.  
  615.             sprintf(s, "%s%c%s", gmp->dname, C_FILESEP, 
  616.                 gmp->current->fname);
  617.  
  618.             if(copy(s, child) < 0){
  619.             /* copy()  will report any error messages */
  620.             break;
  621.             }
  622.             else{            /* highlight new file */
  623.             emlwrite("File copied to %s", child);
  624.  
  625.             if((p = strrchr(child, C_FILESEP)) == NULL){
  626.                 emlwrite("Problems refiguring browser", NULL);
  627.                 break;
  628.             }
  629.  
  630.             *p = '\0';
  631.             strcpy(s, (p == child) ? S_FILESEP: child);
  632.  
  633.             /*
  634.              * new file in same dir? if so, refigure files
  635.              * and redraw...
  636.              */
  637.             if(!strcmp(s, gmp->dname)){ 
  638.                 strcpy(child, gmp->current->fname);
  639.                 if((mp = getfcells(gmp->dname)) == NULL)
  640.                   /* getfcells should explain what happened */
  641.                   break;
  642.  
  643.                 zotmaster(&gmp);
  644.                 gmp = mp;
  645.                 if((tp = FindCell(gmp, child)) != NULL){
  646.                 gmp->current = tp;
  647.                 PlaceCell(gmp, gmp->current, &row, &col);
  648.                 }
  649.  
  650.                 PaintBrowser(gmp, 1);
  651.             }
  652.             }
  653.             break;
  654.           default:
  655.             break;
  656.         }
  657.         }
  658.         BrowserKeys();
  659.         break;
  660.  
  661.       case 'r':                    /* rename */
  662.       case 'R':
  663.         i = 0;
  664.         child[0] = '\0';
  665.  
  666.         if(!strcmp(gmp->current->fname, "..")){
  667.         emlwrite("\007Can't rename \"..\"", NULL);
  668.         break;
  669.         }
  670.  
  671.         if(gmode&MDSCUR){                /* not allowed! */
  672.         emlwrite("Rename not allowed in restricted mode",NULL);
  673.         break;
  674.         }
  675.  
  676.         while(!i){
  677.  
  678.         wkeyhelp("GC0000000000", "Get Help,Cancel");
  679.  
  680.         switch(status=mlreply("Rename file to: ", child, NLINE, QFFILE)){
  681.           case HELPCH:
  682.             emlwrite("\007No help yet!");
  683. /* remove break and sleep after help text is installed */
  684.             sleep(3);
  685.             break;
  686.           case (CTRL|'L'):
  687.             PaintBrowser(gmp, 0);
  688.             break;
  689.           case ABORT:
  690.             emlwrite("Aborted");
  691.             i++;
  692.             break;
  693.           case FALSE:
  694.           case TRUE:
  695.             i++;
  696.  
  697.             if(child[0] == '\0' || status == FALSE){
  698.             mlerase();
  699.             break;
  700.             }
  701.  
  702.             strcpy(s, child);
  703.             sprintf(child, "%s%c%s", gmp->dname, C_FILESEP, s);
  704.  
  705.             status = fexist(child, "w", (long *)NULL);
  706.             if(status == FIOSUC || status == FIOFNF){
  707.             if(status == FIOSUC){
  708.                 sprintf(s,"File \"%s\" exists! OVERWRITE", child);
  709.  
  710.                 if((status = mlyesno(s, FALSE)) != TRUE){
  711.                 if(status ==  ABORT)
  712.                   emlwrite("\007Aborted");
  713.                 else
  714.                   emlwrite("Not Renamed", NULL);
  715.                 break;
  716.                 }
  717.             }
  718.  
  719.             sprintf(s, "%s%c%s", gmp->dname, C_FILESEP, 
  720.                 gmp->current->fname);
  721.  
  722.             if(rename(s, child) < 0){
  723.                 extern int errno;
  724.                 extern char *errstr();
  725.  
  726.                 emlwrite("Rename Failed: %s", errstr(errno));
  727.             }
  728.             else{
  729.                 if((p = strrchr(child, C_FILESEP)) == NULL){
  730.                 emlwrite("Problems refiguring browser", NULL);
  731.                 break;
  732.                 }
  733.                 
  734.                 *p = '\0';
  735.                 strcpy(s, (p == child) ? S_FILESEP: child);
  736.  
  737.                 if((mp = getfcells(s)) == NULL)
  738.                   /* getfcells should explain what happened */
  739.                   break;
  740.  
  741.                 zotmaster(&gmp);
  742.                 gmp = mp;
  743.  
  744.                 if((tp = FindCell(gmp, ++p)) != NULL){
  745.                 gmp->current = tp;
  746.                 PlaceCell(gmp, gmp->current, &row, &col);
  747.                 }
  748.  
  749.                 PaintBrowser(gmp, 1);
  750.                 mlerase();
  751.             }
  752.             }
  753.             else{
  754.             fioperr(status, child);
  755.             }
  756.             break;
  757.           default:
  758.             break;
  759.         }
  760.         }
  761.         BrowserKeys();
  762.         break;
  763.  
  764.       case 's':                    /* user's selected */
  765.       case 'S':
  766.       case (CTRL|'M'):
  767.         if(gmp->current->mode){
  768.         *child = '\0';
  769.  
  770.         while(1){
  771.             i = mlyesno("A directory is selected, enter it", 1);
  772.             if(i == TRUE){
  773.             strcpy(s, gmp->dname);
  774.             p = gmp->current->fname;
  775.             if(p[0] == '.' && p[1] == '.' && p[2] == '\0'){
  776.  
  777.                 if((p=strrchr(s, C_FILESEP)) != NULL){
  778.                 *p = '\0';
  779.  
  780.                 if((gmode&MDSCUR) && homeless(s)){
  781.                     emlwrite("\007Can't visit parent in restricted mode", NULL);
  782.                     break;
  783.                 }
  784.  
  785.                 strcpy(child, &p[1]);
  786.                 if(p == s){        /* is it root? */
  787.                     if(*child)
  788.                       strcpy(s, S_FILESEP);
  789.                     else{
  790.                     emlwrite("\007Can't move up a directory");
  791.                     break;
  792.                     }
  793.                 }
  794.                 }
  795.             }
  796.             else{
  797.                 if(s[1] != '\0')        /* were in root? */
  798.                   strcat(s, S_FILESEP);
  799.                 strcat(s, gmp->current->fname);
  800.             }
  801.  
  802.             if((mp = getfcells(s)) == NULL)
  803.               /* getfcells should explain what happened */
  804.               break;
  805.  
  806.             zotmaster(&gmp);
  807.             gmp = mp;
  808.  
  809.             if(*child){
  810.                 if((tp = FindCell(gmp, child)) != NULL){
  811.                 gmp->current = tp;
  812.                 PlaceCell(gmp, gmp->current, &row, &col);
  813.                 }
  814.                 else
  815.                   emlwrite("\007Problem finding dir \"%s\"",child);
  816.             }
  817.  
  818.             PaintBrowser(gmp, 0);
  819.             break;
  820.             }
  821.             else if(i == FALSE){
  822.             mlerase();
  823.             break;
  824.             }
  825.             else if(i == ABORT){
  826.             emlwrite("Aborted");
  827.             break;
  828.             }
  829.             else if(i == (CTRL|'L')){
  830.             PaintBrowser(gmp, 0);
  831.             }
  832.             else
  833.               (*term.t_beep)();
  834.         }
  835.         }
  836.         else{                /* just return */
  837.         strcpy(dir, gmp->dname);
  838.         strcpy(fn, gmp->current->fname);
  839.         if(sz != NULL)            /* size uninteresting */
  840.           strcpy(sz, gmp->current->size);
  841.         zotmaster(&gmp);
  842.         return(1);
  843.         }
  844.         break;
  845.  
  846.       case 'w':                /* Where is */
  847.       case 'W':
  848.         i = 0;
  849.  
  850.         while(!i){
  851.  
  852.         wkeyhelp("GC0000000000", "Get Help,Cancel");
  853.  
  854.         switch(readpattern("File name to find")){
  855.           case HELPCH:
  856.             emlwrite("\007No help yet!");
  857. /* remove break and sleep after help text is installed */
  858.             sleep(3);
  859.             break;
  860.           case (CTRL|'L'):
  861.             PaintBrowser(gmp, 0);
  862.             break;
  863.           case ABORT:
  864.             emlwrite("Aborted");
  865.             i++;
  866.             break;
  867.           case FALSE:
  868.             mlerase();
  869.             i++;
  870.             break;
  871.           case TRUE:
  872.             if((tp = FindCell(gmp, pat)) != NULL){
  873.             PlaceCell(gmp, gmp->current, &row, &col);
  874.             PaintCell(row, col, gmp->cpf, gmp->current, 0);
  875.             gmp->current = tp;
  876.  
  877.             if(PlaceCell(gmp, tp, &row, &col)){ /* top changed */
  878.                 PaintBrowser(gmp, 1);
  879.             }
  880.             else
  881.               PaintCell(row, col, gmp->cpf, gmp->current, 1);
  882.             mlerase();
  883.             }
  884.             else
  885.               emlwrite("\"%s\" not found", pat);
  886.  
  887.             i++;
  888.             break;
  889.           default:
  890.             break;
  891.         }
  892.         }
  893.         mlerase();
  894.         BrowserKeys();
  895.         break;
  896.  
  897.       case (CTRL|'Z'):
  898.         if(gmode&MDSSPD){
  899.         bktoshell();
  900.         PaintBrowser(gmp,0);
  901.         break;
  902.         }                    /* fall thru with error! */
  903.  
  904.       default:                /* what? */
  905.         if(c < 0xff)
  906.           emlwrite("\007Unknown command: '%c'", c);
  907.         else if(c & CTRL)
  908.           emlwrite("\007Unknown command: ^%c", c&0xff);
  909.         else
  910.           emlwrite("\007Unknown command");
  911.       case NODATA:                /* no op */
  912.         break;
  913.     }
  914.     }
  915. }
  916.  
  917.  
  918.  
  919. /*
  920.  * getfcells - make a master browser struct and fill it in
  921.  *             return NULL if there's a problem.
  922.  */
  923. struct bmaster *getfcells(dname)
  924. char *dname;
  925. {
  926.     int  i, status,                /* various return codes */
  927.          nentries = 0;                /* number of dir ents */
  928.     long l;
  929.     char *np,                    /* names of files in dir */
  930.          *dcp,                    /* to add file to path */
  931.          **filtnames;                /* array filtered names */
  932.     struct fcell *ncp,                /* new cell pointer */
  933.                  *tcp;                /* trailing cell ptr */
  934.     struct bmaster *mp;
  935.     extern int sstrcasecmp();
  936.  
  937.     if((mp=(struct bmaster *)malloc(sizeof(struct bmaster))) == NULL){
  938.     emlwrite("\007Can't malloc space for master filename cell");
  939.     return(NULL);
  940.     }
  941.  
  942.     if(dname[0] == '.' && dname[1] == '\0'){        /* remember this dir */
  943.     if(getcwd(mp->dname, 256) == NULL)
  944.       mp->dname[0] = '\0';
  945.     }
  946.     else if(dname[0] == '.' && dname[1] == '.' && dname[2] == '\0'){
  947.     if(getcwd(mp->dname, 256) == NULL)
  948.       mp->dname[0] = '\0';
  949.     else{
  950.         if((np = (char *)strrchr(mp->dname, C_FILESEP)) != NULL)
  951.           if(np != mp->dname)
  952.         *np = '\0';
  953.     }
  954.     }
  955.     else
  956.       strcpy(mp->dname, dname);
  957.  
  958.     mp->head = mp->top = NULL;
  959.     mp->cpf = mp->fpl = 0;
  960.     mp->longest = 5;                /* .. must be labeled! */
  961.  
  962.     if((mp->names = getfnames(mp->dname, &nentries)) == NULL){
  963.     free((char *) mp);
  964.     return(NULL);
  965.     }
  966.  
  967.     /*
  968.      * this is the fun part.  build an array of pointers to the fnames we're
  969.      * interested in (i.e., do any filtering), then pass that off to be
  970.      * sorted before building list of cells...
  971.      *
  972.      * right now default filtering on ".*" except "..", but this could
  973.      * easily be made a user option later on...
  974.      */
  975.     if((filtnames=(char **)malloc((nentries+1) * sizeof(char *))) == NULL){
  976.     emlwrite("\007Can't malloc space for name array");
  977.     zotmaster(&mp);
  978.     return(NULL);
  979.     }
  980.  
  981.     i = 0;                    /* index of filt'd array */
  982.     np = mp->names;
  983.     while(nentries--){
  984.     if(*np == '.'){                    /* filter .* */
  985.         if(np[1] == '\0' || (np[1] != '.' && np[2] != '\0')){
  986.         np += strlen(np) + 1;
  987.         continue;
  988.         }
  989.     }
  990.  
  991.     filtnames[i++] = np;
  992.  
  993.     if((l = strlen(np)) > mp->longest)    /* cast l ? */
  994.       mp->longest = l;            /* remember longest */
  995.     np += l + 1;                /* advance name pointer */
  996.  
  997.     }
  998.     nentries = i;                /* new # of entries */
  999.  
  1000.     /* 
  1001.      * sort files case independently
  1002.      */
  1003.     qsort((char *)filtnames, nentries, sizeof(char *), sstrcasecmp);
  1004.  
  1005.     /* 
  1006.      * this is so we use absolute path names for stats.
  1007.      * remember: be careful using dname as directory name, and fix mp->dname
  1008.      * when we're done
  1009.      */
  1010.     dcp = (char *)strchr(mp->dname, '\0');
  1011.     dcp[0] = C_FILESEP;
  1012.     dcp[1] = '\0';
  1013.  
  1014.     i = 0;
  1015.     while(nentries--){                /* stat filtered files */
  1016.     /* get a new cell */
  1017.     if((ncp=(struct fcell *)malloc(sizeof(struct fcell))) == NULL){
  1018.         emlwrite("\007Can't malloc cells for browser!");
  1019.         zotfcells(mp->head);        /* clean up cells */
  1020.         free((char *) filtnames);
  1021.         free((char *) mp);
  1022.         return(NULL);            /* bummer. */
  1023.     }
  1024.     ncp->next = ncp->prev = NULL;
  1025.     ncp->mode = 0;
  1026.  
  1027.     if(mp->head == NULL){            /* tie it onto the list */
  1028.         mp->head = mp->top = mp->current = ncp;
  1029.     }
  1030.     else{
  1031.         tcp->next = ncp;
  1032.         ncp->prev = tcp;
  1033.     }
  1034.     tcp = ncp;
  1035.  
  1036.     /* fill in the new cell */
  1037.     ncp->fname = filtnames[i++];
  1038.  
  1039.     strcpy(&dcp[1], ncp->fname);        /* use abolute path! */
  1040.  
  1041.     if(ncp->fname[0] == '.' && ncp->fname[1] == '.' && ncp->fname[2] == '\0'){
  1042.         ncp->mode = 1;                /* parent is special */
  1043.         strcpy(ncp->size, "(parent dir)");
  1044.     }
  1045.     else if(isdir(mp->dname, &l)){
  1046.         ncp->mode = 1;
  1047.         strcpy(ncp->size, "(dir)");
  1048.     }
  1049.     else
  1050.       strcpy(ncp->size,  prettysz(l));
  1051.     }
  1052.  
  1053.     *dcp = '\0';                /* remember to cap dname */
  1054.     free((char *) filtnames);            /* 'n blast filt'd array*/
  1055.  
  1056.     layoutcells(mp);
  1057.  
  1058.     return(mp);
  1059. }
  1060.  
  1061.  
  1062.  
  1063. /*
  1064.  * PaintCell - print the given cell at the given location on the display
  1065.  *             the format of a printed cell is:
  1066.  *
  1067.  *                       "<fname>       <size>  "
  1068.  */
  1069. PaintCell(x, y, l, cell, inverted)
  1070. struct fcell *cell;
  1071. int    x, y, l, inverted;
  1072. {
  1073.     char *p;                    /* temp str pointer */
  1074.     int   i = 0,                /* current display count */
  1075.           j, sl, fl;                /* lengths */
  1076.  
  1077.     if(cell == NULL)
  1078.     return(-1);
  1079.  
  1080.     fl = strlen(cell->fname);
  1081.     sl = strlen(cell->size);
  1082.  
  1083.     movecursor(x, y);
  1084.     if(inverted)
  1085.       (*term.t_rev)(1);
  1086.     
  1087.     /* room for fname? */
  1088.     p = (fl+2 > l) ? &cell->fname[fl-(l-2)] : cell->fname;
  1089.     while(*p != '\0'){                /* write file name */
  1090.     pputc(*p++);
  1091.     i++;
  1092.     }
  1093.  
  1094.     if(sl+3 <= l-i){                /* room for size? */
  1095.     j = (l-i)-(sl+2);            /* put space between */
  1096.     i += j;
  1097.     while(j--)                /* file name and size */
  1098.       pputc(' ');
  1099.  
  1100.     p = cell->size;
  1101.     while(*p != '\0'){            /* write file size */
  1102.         pputc(*p++);
  1103.         i++;
  1104.     }
  1105.     }
  1106.  
  1107.     if(inverted)
  1108.       (*term.t_rev)(0);
  1109.  
  1110.     while(i++ < l)                /* pad ending */
  1111.       pputc(' ');
  1112.  
  1113.     return(1);
  1114. }
  1115.  
  1116.  
  1117.  
  1118. /*
  1119.  * PaintBrowse - with the current data, display the browser.  if level == 0 
  1120.  *               paint the whole thing, if level == 1 just paint the cells
  1121.  *               themselves
  1122.  */
  1123. PaintBrowser(mp, level)
  1124. struct bmaster *mp;
  1125. int level;
  1126. {
  1127.     int i, cl;
  1128.     struct fcell *tp;
  1129.  
  1130.     if(!level){
  1131.     cl = (Pmaster) ? term.t_nrow : term.t_nrow - 1;
  1132.     for(i = 0; i <= cl; i++){        /* clear screen */
  1133.         movecursor(i, 0);
  1134.         peeol();
  1135.     }
  1136.  
  1137.     BrowserAnchor(mp->dname);
  1138.     }
  1139.  
  1140.     i = 0;
  1141.     tp = mp->top;
  1142.     cl = COMPOSER_TOP_LINE;            /* current display line */
  1143.     while(tp){
  1144.  
  1145.     PaintCell(cl, mp->cpf * i, mp->cpf, tp, tp == mp->current);
  1146.  
  1147.     if(++i >= mp->fpl){
  1148.         i = 0;
  1149.         if(++cl > term.t_nrow-3)
  1150.           break;
  1151.     }
  1152.  
  1153.     tp = tp->next;
  1154.     }
  1155.  
  1156.     if(level){
  1157.     while(cl <= term.t_nrow - 3){
  1158.         if(!i)
  1159.           movecursor(cl, 0);
  1160.         peeol();
  1161.         movecursor(++cl, 0);
  1162.     }
  1163.     }
  1164.     else{
  1165.     BrowserKeys();
  1166.     }
  1167.  
  1168.     return(1);
  1169. }
  1170.  
  1171.  
  1172. /*
  1173.  * BrowserKeys - just paints the keyhelp at the bottom of the display
  1174.  */
  1175. BrowserKeys()
  1176. {
  1177.     char *oldkeys;
  1178.  
  1179.     /* reassign HelpKeyNames temporarily */
  1180.     oldkeys = HelpKeyNames;
  1181.     if(!(gmode&MDFKEY))
  1182.       HelpKeyNames = "~?,~C,~R,~-,~D,~M,~S,~G,~W,~ ,~U,~K,                             "; 
  1183.     
  1184.     wkeyhelp("GCR-DMSJW 00", "Help,Cancel,Rename,Back Pg,Del File,Make Copy,Select,Goto Dir,Where is,Fwd Pg");
  1185.     
  1186.     if(!(gmode&MDFKEY))
  1187.       HelpKeyNames = oldkeys;            /* retore HelpKeyNames */
  1188. }
  1189.  
  1190.  
  1191. /*
  1192.  * layoutcells - figure out max length of cell and how many cells can 
  1193.  *               go on a line of the display
  1194.  */
  1195. layoutcells(mp)
  1196. struct bmaster *mp;
  1197. {
  1198.     int i = 1;
  1199.  
  1200.     mp->cpf = mp->longest + 12;            /* max chars / file */
  1201.  
  1202.     while(i*mp->cpf < term.t_ncol)        /* no force... */
  1203.       i++;                    /* like brute force! */
  1204.  
  1205.     mp->fpl = i - 1;                /* files per line */
  1206. }
  1207.  
  1208.  
  1209. /*
  1210.  * PlaceCell - given a browser master, return row and col of the display that
  1211.  *             it should go.  
  1212.  *
  1213.  *             return 1 if mp->top has changed, x,y relative to new page
  1214.  *             return 0 if otherwise (same page)
  1215.  *             return -1 on error
  1216.  */
  1217. PlaceCell(mp, cp, x, y)
  1218. struct bmaster *mp;
  1219. struct fcell *cp;
  1220. int    *x, *y;
  1221. {
  1222.     int cl = COMPOSER_TOP_LINE;            /* current line */
  1223.     int ci = 0;                    /* current index on line */
  1224.     int rv = 0;
  1225.     int secondtry = 0;
  1226.     struct fcell *tp;
  1227.  
  1228.     /* will cp fit on screen? */
  1229.     tp = mp->top;
  1230.     while(1){
  1231.     if(tp == cp){                /* bingo! */
  1232.         *x = cl;
  1233.         *y = ci * mp->cpf;
  1234.         break;
  1235.     }
  1236.  
  1237.     if((tp = tp->next) == NULL){        /* above top? */
  1238.         if(secondtry++){
  1239.         emlwrite("\007Internal error: can't find fname cell");
  1240.         return(-1);
  1241.         }
  1242.         else{
  1243.         tp = mp->top = mp->head;    /* try from the top! */
  1244.         cl = COMPOSER_TOP_LINE;
  1245.         ci = 0;
  1246.         rv = 1;
  1247.         continue;            /* start over! */
  1248.         }
  1249.     }
  1250.  
  1251.     if(++ci >= mp->fpl){            /* next line? */
  1252.         ci = 0;
  1253.         if(++cl > term.t_nrow-3){        /* next page? */
  1254.         ci = mp->fpl;            /* tp is at bottom right */
  1255.         while(ci--)            /* find new top */
  1256.           tp = tp->prev;
  1257.         mp->top = tp;
  1258.         ci = 0;
  1259.         cl = COMPOSER_TOP_LINE;        /* keep checking */
  1260.         rv = 1;
  1261.         }
  1262.     }
  1263.  
  1264.     }
  1265.  
  1266.     /* not on display! */
  1267.     return(rv);
  1268.     
  1269. }
  1270.  
  1271.  
  1272. /*
  1273.  * zotfcells - clean up malloc'd cells of file names
  1274.  */
  1275. zotfcells(hp)
  1276. struct fcell *hp;
  1277. {
  1278.     struct fcell *tp;
  1279.  
  1280.     while(hp){
  1281.     tp = hp;
  1282.     hp = hp->next;
  1283.     tp->next = NULL;
  1284.     free((char *) tp);
  1285.     }
  1286. }
  1287.  
  1288.  
  1289. /*
  1290.  * zotmaster - blast the browser master struct
  1291.  */
  1292. zotmaster(mp)
  1293. struct bmaster **mp;
  1294. {
  1295.     zotfcells((*mp)->head);            /* free cells       */
  1296.     free((char *)(*mp)->names);            /* free file names  */
  1297.     free((char *)*mp);                /* free master      */
  1298.     *mp = NULL;                    /* make double sure */
  1299. }
  1300.  
  1301.  
  1302. /*
  1303.  * FindCell - starting from the current cell find the first occurance of 
  1304.  *            the given string wrapping around if necessary
  1305.  */
  1306. struct fcell *FindCell(mp, string)
  1307. struct bmaster *mp;
  1308. char   *string;
  1309. {
  1310.     struct fcell *tp, *fp;
  1311.  
  1312.     if(*string == '\0')
  1313.       return(NULL);
  1314.  
  1315.     fp = NULL;
  1316.     tp = mp->current->next;
  1317.     
  1318.     while(tp && !fp){
  1319.     if(sisin(tp->fname, string))
  1320.       fp = tp;
  1321.     else
  1322.       tp = tp->next;
  1323.     }
  1324.  
  1325.     tp = mp->head;
  1326.     while(tp != mp->current && !fp){
  1327.     if(sisin(tp->fname, string))
  1328.       fp = tp;
  1329.     else
  1330.       tp = tp->next;
  1331.     }
  1332.  
  1333.     return(fp);
  1334. }
  1335.  
  1336.  
  1337. /*
  1338.  * sisin - case insensitive substring matching function
  1339.  */
  1340. sisin(s1, s2)
  1341. char *s1, *s2;
  1342. {
  1343.     register int j;
  1344.  
  1345.     while(*s1){
  1346.     j = 0;
  1347.     while(toupper(s1[j]) == toupper(s2[j]))
  1348.       if(s2[++j] == '\0')            /* bingo! */
  1349.         return(1);
  1350.  
  1351.     s1++;
  1352.     }
  1353.     return(0);
  1354.  
  1355.  
  1356. /*
  1357.  * BrowserAnchor - draw the browser's anchor line.
  1358.  */
  1359. BrowserAnchor(dir)
  1360. char *dir;
  1361. {
  1362.     register char *p;
  1363.     register int  i, j, l;
  1364.  
  1365.     movecursor(0, 0);
  1366.     (*term.t_rev)(1);
  1367.  
  1368.     i = 0;
  1369.     l = strlen(dir);
  1370.     j = (term.t_ncol-(l+16))/2;
  1371.  
  1372.     if(Pmaster)
  1373.       sprintf(s,"   PINE %s ", Pmaster->pine_version);
  1374.     else
  1375.       sprintf(s,"   PICO %s ", version);
  1376.  
  1377.     p = s;
  1378.     while(*p){
  1379.     pputc(*p++);
  1380.     i++;
  1381.     }
  1382.  
  1383.     if(l > term.t_ncol - i - 21){        /* fit dir name on line */
  1384.     p = dir;
  1385.     while((p = strchr(p, C_FILESEP)) != NULL)
  1386.       if((l - (p - dir)) <= term.t_ncol - i - 21)
  1387.         break;
  1388.       else
  1389.         p++;
  1390.  
  1391.     if(*p == '\0')                /* no suitable length! */
  1392.       p = &dir[l-(term.t_ncol-i-19)];
  1393.  
  1394.     sprintf(s,"BROWSER   Dir ...%s", p);
  1395.     }
  1396.     else 
  1397.       sprintf(s,"BROWSER    Dir: %s",dir);
  1398.  
  1399.     if(i < j)                    /* keep it centered */
  1400.       j = j - i;                /* as long as we can */
  1401.     else
  1402.       j = ((term.t_ncol-i)-(strlen(p)+15))/2;
  1403.  
  1404.     while(j-- && i++)
  1405.       pputc(' ');
  1406.     p = s;
  1407.  
  1408.     while(i++ < term.t_ncol && *p)        /* show directory */
  1409.       pputc(*p++);
  1410.  
  1411.     while(i++<term.t_ncol)
  1412.       pputc(' ');
  1413.  
  1414.     (*term.t_rev)(0);
  1415. }
  1416.  
  1417.  
  1418. /*
  1419.  * ResizeBrowser - handle a resize event
  1420.  */
  1421. ResizeBrowser()
  1422. {
  1423.     if(gmp){
  1424.     layoutcells(gmp);
  1425.     PaintBrowser(gmp, 0);
  1426.     return(1);
  1427.     }
  1428.     else
  1429.       return(0);
  1430. }
  1431.